package com.jmp.autocofiguration;

import com.google.common.base.Optional;
import com.google.common.collect.Multimap;
import io.swagger.models.Operation;
import io.swagger.models.Path;
import io.swagger.models.Swagger;
import org.apache.commons.lang3.StringUtils;
import springfox.documentation.service.ApiDescription;
import springfox.documentation.service.ApiListing;
import springfox.documentation.service.Documentation;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2MapperImpl;

import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

import static com.google.common.collect.Maps.newTreeMap;
import static springfox.documentation.builders.BuilderDefaults.nullToEmptyList;

/**
 * @author cjr
 */
public class ServiceModelToSwagger2MapperImplExt extends ServiceModelToSwagger2MapperImpl {

    @Override
    public Swagger mapDocumentation(Documentation from) {
        Swagger swagger = super.mapDocumentation(from);
        swagger.setPaths(mapApiListings(from.getApiListings()));
        return swagger;
    }

    @Override
    protected Map<String, Path> mapApiListings(Multimap<String, ApiListing> apiListings) {
        Map<String, Path> paths = newTreeMap();
        for (ApiListing each : apiListings.values()) {
            for (ApiDescription api : each.getApis()) {
                paths.put(api.getPath(), mapOperations(api, Optional.fromNullable(paths.get(api.getPath()))));
            }
        }

        Comparator<Map.Entry<String, Path>> comparator = (left, right) -> {
            String leftPos = left.getValue().getOperations().size() == 1 ? left.getValue().getOperations().get(0).getTags() + left.getValue().getOperations().get(0).getSummary() : StringUtils.EMPTY;
            String rightPos = right.getValue().getOperations().size() == 1 ? right.getValue().getOperations().get(0).getTags() + right.getValue().getOperations().get(0).getSummary() : StringUtils.EMPTY;

            int position = StringUtils.compare(leftPos, rightPos);
            if (position == 0) {
                position = left.getValue().getOperations().get(0).getOperationId().compareTo(right.getValue().getOperations().get(0).getOperationId());
            }

            return position;
        };
        paths = paths.entrySet().stream().sorted(comparator)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));

        return paths;
    }

    private Path mapOperations(ApiDescription api, Optional<Path> existingPath) {
        Path path = existingPath.or(new Path());
        for (springfox.documentation.service.Operation each : nullToEmptyList(api.getOperations())) {
            Operation operation = mapOperation(each);
            path.set(each.getMethod().toString().toLowerCase(), operation);
        }
        return path;
    }
}
